// 车站网络,用于储存两个车站之间的路径
/**
 * 所有车站的位置两个房间交界的地方
 *      1.同shard的相邻房间->房间出口
 *      2.通过星门链接的房间->星门
 *
*/
/**
 * 两个站点确定一条固定的路径.星门不能作为起点站
*/
 
import { UtilsHelper } from "utils/position/UtilsHelper";
import { CacheOper } from "./CacheOperator";
import { CostKeys, PathFinderManager } from "./PathFinderManager";
import { interval_execute, memory_cache } from "utils/decorate/decorate";
import { PositionHelper } from "utils/position/PositionHelper";


interface ICacheRoomPosition extends RoomPosition
{
     
    index:number;
}
class RoadSegment<T extends ICacheRoomPosition> 
{
    roadKey!:string;    // 路径的key
    roadSegment!:T[] // 路径段.在这个指定区域内的路径坐标点
    constructor (key:string,segments:T[] )
    {
        this.roadKey = key;
        this.roadSegment = segments
    }
}
class RoomCeil<T extends ICacheRoomPosition> 
{
    index:number;
    segment:Map<string,RoadSegment<T>>;//
    constructor(index:number)
    {
        this.index = index;
        this.segment = new Map()
    }

    public pushPos(roadKey:string,pos:T)
    {
        const pathsegment = this.segment.get(roadKey);
        if(pathsegment)
        {
            pathsegment.roadSegment.push(pos);
        }
        else 
        {
            // 新增
            this.segment.set(roadKey,new RoadSegment(roadKey,[pos]));
        }
    }
}
/**
 * 寻路缓存,目前就只缓存修路路径呗
 */
/*@profile*/
export class PathCacheManager<T extends ICacheRoomPosition> 
{
    // 把房间划分成100个网格
    private _cache:Record<string,T[]>={};    // 路径缓存
    private _roomCeils:Map<string,RoomCeil<T>[]> =new Map();   // 房间对应的网格
    /**
     * 添加路径
     * @param from 
     * @param to 
     * @param cache 
     */
    public addPath(key:string,path:RoomPosition[])
    {
        const poss = path.map((e,index)=>{
            const p:ICacheRoomPosition = new RoomPosition(e.x,e.y,e.roomName) as any;
                p.index = index
            return p }) as T[];;
        // const key = this.stanardkey(path[0],path[path.length-1]);
        this._cache[key] = poss;
        // 添加路径
        for(const e of poss)
        {
            if(!this._roomCeils.get(e.roomName))
            {
                // 初始化房间路径缓存
                this.initRoomCeil(e.roomName);
            }
            const ceils = this._roomCeils.get(e.roomName)!;
            // 在边沿的两边都插,增加搜索范围
            const index = this.getCeilIndex(e);
            ceils[index].pushPos(key,e);
        }
    }

    
    /**
     * 查找房间的缓存,本房间所有的road 计划
     * 主要用来给查找修路点，作数据参考
     * @param roomName 
     * @return Roomposition[] 房间内的修路缓存
     */ 
    public findRoomCache(roomName:string)
    {
        const ceils = this._roomCeils.get(roomName);
        if(ceils)
        {
            let allPathRoad:RoomPosition[] = [];
            for(const c of ceils)
            {
                c.segment.forEach((v,k)=>{
                    allPathRoad =  allPathRoad.concat(v.roadSegment.map(e=>e))
                })
            }
            return allPathRoad;
        }   
        return []
    }

    /**
     * 查找从起点到终点是否存在路径缓存
     * 1.起点一定在路径上
     * 2.终点所在的网格内一定存在路径
     * 3.起点和终点查找到的路径缓存 都存在的路径则为这次寻路的有效路径缓存。可以使用
     * 
     * ####注意 跨房间时，可能路由是相同的。可以适当放大终点的查找范围
     * @param from 起点
     * @param to 终点
     * @returns 
     */
    public findPathCache(from:RoomPosition,to:RoomPosition,isdebug=false):{key:string,value:string}|false
    {
        // 1.判断起点是否在路径上
        // 2.查找终点附近是否有路
        // 3.判断路径是否有重叠
        // 4.截取路径返回
        const isStartPath = this.isNearPath(from);
        if (!isStartPath) {
            return false;
        }

        const findEndPathKey = (f:RoomPosition,t:RoomPosition,startPaths:string[])=>
        {
            // const startPaths = this.findStandPath(f);
            // if (!startPaths) {
            //     return false;
            // }
                // 2.查找终点附近是否有路
            const endPaths = this.findRangePath(t);
            if (!endPaths) {
                return false;
            }
            
            // 3.判断路径是否有重叠
            const pathkey = startPaths.find(e=> endPaths.has(e));
            if(pathkey)
            {
                return {
                    key:pathkey,
                    value:endPaths
                }
            }
            if(f.roomName !== t.roomName)
            {
                for(let i=1;i<=2;i++)
                {
                    const endPathnew = this.findRangePathInRange(t,i);
                    if(endPathnew)
                    {
                        for(const path of endPathnew)
                        {
                            const pathkey = startPaths.find(e=>path.has(e));
                            if(pathkey)
                            {
                                return {
                                    key:pathkey,
                                    value:path
                                }
                            }
                        }
                       
                    }
                }
            }            
            return false;
        }
        // 2.查找起点附近是否有路
        const startPaths = this.findNearPath(from);
        if (!startPaths) {
            return false;
        }
         // 2.查找终点附近是否有路
        // const endPaths = this.findRangePath(to);
        // if (!endPaths) {
        //     return false;
        // }
        
        // 3.判断路径是否有重叠
        const pathpair = findEndPathKey(from,to,startPaths);
        if(!pathpair)
        {
            return false
        }
        const pathkey = pathpair?.key;
        const startCeils = this.findRangePath(from);
        if(!startCeils)
        {
            return false
        }
        const nestestStart = _.find(startCeils.get(pathkey)!.roadSegment,e=>e.isNearTo(from));
        if(!nestestStart)
        {
            return false;
        }
        const nesrestEnd = _.min(pathpair.value.get(pathkey)!.roadSegment,e=>e.distance(to));
       
        
        // 4.截取路径返回
        const pathcache =     this._cache[pathkey];
        if(!pathcache)
        {
            return false;
        }
        const path = this.splicePath(pathcache,nestestStart.index ,nesrestEnd.index ,isdebug);
        if(isdebug)
        {
            console.log(`pathkey ${pathkey} from:${JSON.stringify(from)}->to:${JSON.stringify(to)} 靠近: ${JSON.stringify(nesrestEnd)}`);
            console.log(`截取路径 ${JSON.stringify(path)}`);
        }
        if(path)
        {
            // 再次裁一遍, 找到与起点最近的坐标
            let i=0;
            for(;i<path.length;i++)
            {
                const p = path[i];
                if(!p.isNearTo(from))
                {
                    break;
                }
            }
            // 第 0个必然与起点相同或者相邻
            path.splice(0,i-1,from as T);
            return {key:pathkey,value:UtilsHelper.serializePath( path)};
        }
        return false;
    }
    private initRoomCeil(roomName:string)
    {
        const ceils:RoomCeil<T>[]=[];
        for(let i=0;i<100;i++)
        {
            ceils.push(new RoomCeil(i));
        }
        this._roomCeils.set(roomName,ceils)
    }
    public isStandPath(p:RoomPosition)
    {
        const ceils = this._roomCeils.get(p.roomName);
        if(!ceils)
        {
            return false;
        }
        const index =this.getCeilIndex(p);
        let val = false;
        ceils[index].segment.forEach((v,k)=>
        {
            for(const e of v.roadSegment)
            {
                if(e.isEqualTo(p))
                {
                    val = true;
                    return 
                }
            }
        })
        return val
    }
    private isNearPath(p:RoomPosition)
    {
        const ceils = this._roomCeils.get(p.roomName);
        if(!ceils)
        {
            return false;
        }
        const index =this.getCeilIndex(p);
        let val = false;
        ceils[index].segment.forEach((v,k)=>
        {
            for(const e of v.roadSegment)
            {
                if(e.isNearTo(p))
                {
                    val = true;
                    return 
                }
            }
        })
        return val
    }
    private findNearPath(p:RoomPosition)
    {
        const ceils = this._roomCeils.get(p.roomName);
        if(!ceils)
        {
            return false;
        }
        const index =this.getCeilIndex(p);
        const path:string[]=[];
        const path2:string[]=[];
        ceils[index].segment.forEach((v,k)=>
        {
            for(const e of v.roadSegment)
            {
                if(e.isEqualTo(p))
                {
                    path.push(k);
                    //break;
                }
                else if (e.isNearTo(p))
                {
                    path2.push(k);
                }
            }
        })
        return path.length?path:(path2.length?path2:false)
    }
    private findRangePath(p:RoomPosition )
    {
        const ceils = this._roomCeils.get(p.roomName);
        if(!ceils)
        {
            return false;
        }
        const index =this.getCeilIndex(p);
        return ceils[index].segment 
    }
    private findRangePathInRange(p:RoomPosition,range:number=1)
    {
        const ceils = this._roomCeils.get(p.roomName);
        if(!ceils)
        {
            return false;
        }
        const index =this.getCeilRangeIndex(p,range);
        return   index.map(e=>ceils[e].segment)
    }
    private splicePath(paths:T[],start:number,end:number,isdebug=false)
    {
        if(start<end)
        {
            if(isdebug)
            {
                console.log(`截取路径[${start}]->[${end}] ${JSON.stringify(paths.slice(start,end+1))}`);
                Memory.Debug['cachepath']=paths.slice(start,end+1);
            }
            
            return   paths.slice(start,end+1)
        }
        else if(start>end)
        {
            if(isdebug)
            {
                console.log(`截取路径[${start}]->[${end}]  ${JSON.stringify(paths.slice(start,end+1))}`);
                Memory.Debug['cachepath']=paths.slice(end,start+1).reverse();
            }
            return  paths.slice(end,start+1).reverse() 
        }
        else 
        {
            if(isdebug)
            {
                console.log(`截取路径 失败  ${start} == ${end}`);
            }
        }
        return false;
    }
    /**
     * 获取路径的子路径
     * @param from 
     * @param to 
     * @param pathkey 
     */
    private getSubPath(from:RoomPosition, to:RoomPosition, pathkey:string,isdebug=false)
    {
        const paths = this._cache[pathkey];
        if(!paths)
        {
            global.Log.Info(`找不到路径 ${from}->${to}`)
        }
        let start=-1,end=-1;
        for(let i=0;i<paths.length;i++)
        {
            if(paths[i].isEqualTo(from))
            {
                start = i;
            }
            else if(paths[i].isEqualTo(to))
            {
                end = i;
            }
            if(start>-1 && end>-1)
            {
                const path =  this.splicePath(paths,start,end,isdebug);
                if(path)
                {
                    return path
                }
            }
        }
        if(isdebug)
        {
            if(paths.findIndex(e=>e.isEqualTo(from)) == -1 )
            {
                console.log(`起点 ${JSON.stringify(from)}不在路径上 ${JSON.stringify(paths)}`);
            }
            if(paths.findIndex(e=>e.isEqualTo(to)) ==-1 )
            {
                console.log(`终点 ${JSON.stringify(to)}不在路径上 ${JSON.stringify(paths)}`);
            }
            console.log(`起点或终点不在路径上 ${JSON.stringify(from)} ${JSON.stringify(to)}  path:${JSON.stringify(paths)}`);
        }
        
        return false
    }
    private getCeilIndex(p:RoomPosition)
    {
        return Math.floor( p.x/5)+Math.floor( p.y/5)*10;
    }

    private getCeilRangeIndex(p:RoomPosition,range:number=0)
    {
        const x_ = Math.floor( p.x/5);
        const y_ = Math.floor( p.y/5);
        if(range ==0)
        {
            return [x_+y_*10];
        }
        else
        {
            const findRangeIndex=(x:number,y:number,range:number)=>
            {
                const index:[number,number][]=[];
                const offset = [ - range,   range];
                for(let n=offset[0];n<offset[1];n++)
                {
                    let nx = x+n;
                    let ny =  y-range;
                    index.push([nx,ny ]);
                }
                // +x y+
                for(let n=offset[0];n<offset[1];n++)
                {
                    let nx = x+range;
                    let ny =  y+n;
                    index.push([nx,ny ]);
                }
                // x- +y
                for(let n=offset[1];n>offset[0];n--)
                {
                    let nx = x+n;
                    let ny =  y+range;
                    index.push([nx,ny ]);
                }
                // -x y-
                for(let n=offset[1];n>offset[0];n--)
                {
                    let nx =  x-range;
                    let ny =  y+n;
                    index.push([nx,ny ]);
                }
                return index
            }
            return findRangeIndex(x_,y_,range).filter(e=>e[0]>=0&&e[1]>=0&&e[0]<=9&&e[1]<=9).map(e=>e[0]+e[1]*10);
        }
        // return Math.floor( p.x/5)+Math.floor( p.y/5)*10;
    }


    /**
     * 标准化_key两点之间坐标key
     * @param from 
     * @param to 
     * @returns 
     */
    private stanardkey(from:IRoomPosition,to:IRoomPosition):string
    {
        return `${UtilsHelper.serializePos(from)}_${UtilsHelper.serializePos(to)}`
    }
}
/**
 * 用于查询从房间A到房间B的车站路径
 * 
 * 需要调整。当 roomA-> roomB 的出口不止一个时。这个房间不能作为有站点的
 */
 /*@profile*/
export class StationNetwork
{
    private static instance: StationNetwork
    private _roomPathCacheHeap:Record<string,ITCacheData<IRouteCache>> ={};
    static get getInstance() {
        if (!StationNetwork.instance) {
            StationNetwork.instance = new StationNetwork();
            StationNetwork.instance.init();
        }
        return StationNetwork.instance
    }
    private _pathFinder!:PathFinderManager;
    // @memory_cache(["station"])
    private get _avoidRooms():Record<string,number>      // 禁止通行的房间
    {
        return Memory.Data["station"]._avoidRooms
    }
    private set _avoidRooms(val:any)       // 禁止通行的房间
    {
          Memory.Data["station"]['_avoidRooms']=val;
    }

    private _portalPath!:Record<string,ITCacheData<IPortalPath>>; // 星门地图
    
    private get _roomPath():Record<string,ITCacheData<IRouteCache>>  // 路径地图
    {
        return this._roomPathCacheHeap
        // return Memory.Data["station"]._roomPath
    }
    private set _roomPath(val:any)       // 禁止通行的房间
    {
        //   Memory.Data["station"]['_roomPath']=val;
          this._roomPathCacheHeap = val;
    }
    private get _normal_paths():Record<string,ITCacheData<INormalPath>> // 点到点的一般路径
    {
        return Memory.Data["station"]._normal_paths
    }
    private set _normal_paths(val:any)       // 禁止通行的房间
    {
          Memory.Data["station"]['_normal_paths']=val;
    }
    private _pathCache:PathCacheManager<ICacheRoomPosition>;
    private constructor()
    {
        this._pathFinder = new PathFinderManager(this);
        this._pathCache = new PathCacheManager();
        // this.init();
    }
    private init()
    {
        if(!Memory.Data)
        {
            Memory.Data={};
        }
        if(!Memory.Data["station"])
        {
            Memory.Data["station"]={};
        }
        if(!this._portalPath)
        {
            this._portalPath = {};
        }
        if(!this._roomPath)
        {
            this._roomPath = {};
            
        }
        // if(!this._stop_paths)
        // {
        //     this._stop_paths = {};
        // }
        // if(!this._stopmap)
        // {
        //     this._stopmap = {};
        // }
        if(!this._avoidRooms)
        {
            this._avoidRooms = {};
            
        }
        if(!this._normal_paths)
        {
            this._normal_paths={};
        }
        for(const k in this._normal_paths)
        {
            const e  = this._normal_paths[k];
            const path = UtilsHelper.deserializePathCache(e.data.path)
            this._pathCache.addPath(k,path);
           
        }
    }
    public get PathFinder()
    {
        return this._pathFinder;
    }
    public get PathCache()
    {
        return this._pathCache;
    }
    public get AvoidRoom()
    {
        return this._avoidRooms;
    }
    /**
     * 缓存复位
     */
    public reset()
    {
        this._portalPath = {};
        this._roomPath = {};
        // this._stop_paths = {};
        // this._stopmap = {};
        this._avoidRooms = {};
        this._normal_paths={};
    }
    @interval_execute("interval",30000)
    public update()
    {
        const checkpath=(data:Record<string, ITCacheData<any>>,interval:number)=>
        {
            const keys  = Object.keys(data);

            for(const e of keys)
            {
                const delta = Game.time-data[e].firsttime;
                const avgspan = delta/data[e].time; // 平均执行间隔
                if(avgspan>interval)
                {
                    // 站点路径
                    delete data[e];
                }
            }
        }
        // checkpath(this._stop_paths,50000);
        // checkpath(this._roomPath,30000);
    }
    public addAvoidRoom(roomName:string,time:number=-1)
    {
        const keys = Object.keys(this._roomPath)
        for(const key of keys)
        {
           if(this._roomPath[key].data.route.findIndex(e=>e==roomName)>-1)
           {
               delete this._roomPath[key];
           }
        }
         if(this._avoidRooms[roomName])
         {
             return ;
         }
         
         if(time== -1)
         { 
            this._avoidRooms[roomName]=-1;
            
         }
         else 
         {
           this._avoidRooms[roomName]=Game.time+time;
         }
         
    }
    /**
     * 查找房间路由
     * @param from 起点房间
     * @param to 终点房间
     * @param isusePortal
     */
    public findPortalRoute(from:IPortalInput,to:IPortalInput ):ICacheResult<IPortalPath>
    {
        // 先查询缓存
        const routekey = `${from.shard}/${from.room}_${to.shard}/${to.room}`;
        let cache =CacheOper.getCache(this._portalPath,routekey);
        if(cache)
        {
            return cache;
        }
        const portalpath = global.wasmLib.find_portal_route(from,to);
        if(portalpath)
        {
            CacheOper.insertCache(this._portalPath,portalpath,routekey);
            return {key:routekey,value:portalpath};
        }
        if(Game.cpu.bucket>300)
        {
            global.wasmLib.init_portal();
        }
        throw new Error(`星门寻路失败`);
    }
     /**
     * 查找房间路由
     * @param from 起点房间
     * @param to 终点房间
     * @param isusePortal
     */
    public findRoute(from:string,to:string,highwaycost=1):ICacheResult<IRouteCache>|false
    {
        if(from == to)
        {
            return  {key:`${from}_${to}`,value:{route:[from],index:0}};
        }
        const RoomRouteKey = `${from}_${to}`;
        let cache =CacheOper.getCache(this._roomPath,RoomRouteKey);

        if(cache)
        {
            return cache;
        }
        else
        {
            const RoomRouteKey2 = `${to}_${from}`;
            cache =CacheOper.getCache(this._roomPath,RoomRouteKey2);
            if(cache)
            {
                const reversecache = _.cloneDeep(cache);
                reversecache.value.route =reversecache.value.route.reverse();
                reversecache.key = RoomRouteKey;
                if(reversecache.value.route[0]!== from)
                {
                    throw new Error(`查找到的路由不一致 ${ RoomRouteKey}->${JSON.stringify( reversecache.value.route )}  原始路由:${JSON.stringify(cache.value)}`);
                }
                return reversecache;
            }
        }

        const ret = this._findRoute(from,to,highwaycost);
        if(ret)
        {
            CacheOper.insertCache<IRouteCache>(this._roomPath,{route:ret,index:0},RoomRouteKey);
            return  {key:RoomRouteKey,value:{route:ret,index:0}};
        }
        return false;
    }
   
    public clearPath(key:string)
    {
        // 清理过期的路径
   
        // delete this._stop_paths[key];
        // this._normal_paths[key] =  undefined as any;
        Memory.Data["station"]['_normal_paths'][key]= undefined
    }
    public searchRoad(origin: RoomPosition,goal: { pos: RoomPosition; range: number },opt:IPathFinderOpt)
    {
        const route = this.findRoute(origin.roomName,goal.pos.roomName);
        if(route)
        {
            opt.route = route.value.route;
           
        }
        opt.PathCost={swampCost:3,plainCost:2}
        return this.PathFinder.searchPath(origin,goal,opt,["c_structureplan","c_roadplan","c_position"])
    }
    /**
     * 
     * @param origin 判断点坐标两格内是否有路
     * @returns 
     */
    public isExistRoadNearPosition(origin:RoomPosition)
    {
        const ret = (this._pathCache as any).findRangePath(origin);
        return ret?true:false
        
    }
    /**
     * 添加路径缓存
     * @param origin 
     * @param path 
     * @returns 
     */
    public addRoadCache(origin:RoomPosition,path: PathFinderPath)
    {
       
        const key = this.stanardkey(origin, path.path[ path.path.length-1]);
        const pathcache = UtilsHelper.serializePathResult(origin,path);
        if(path.path.length &&  !path.path[0].isEqualTo(origin))
        {
            path.path.splice(0,0,origin);
        }
        this.PathCache.addPath(key,path.path)
        return this.insertPathCache(key,origin,pathcache);
    }
    /**
     * 查找从origin 到 rooma-roomb 的出口位置的寻路,实时寻路无法缓存.
     * ?是否可以通过设置最大寻路房间数量为1，来寻到出口的路
     * @param origin 
     * @param goal 
     * @param opt 
     * @param decorates 
     * @returns 
     */
    public searchPathToExit(origin: RoomPosition,goal: {rooma:string,roomb:string},opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"] ): ICacheResult<Readonly<INormalPath>> 
    {
        const ret =  this.PathFinder.searchPathToExit(origin,goal,opt,decorates);
        return {key:"def"+`realtime`,value:{path:{pos:UtilsHelper.serializePos(origin),cache:ret.cache}}}
        
    }
    public searchPathOneRoom(origin: RoomPosition,goal: RoomPosition,opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"] ): ICacheResult<Readonly<INormalPath>> 
    {
        if(opt.IsEludeHostile)
        {
            decorates.push("c_elude");
        }

        const ret =  this.PathFinder.searchPathOneRoom(origin,goal,opt,decorates);
        
        if(ret)
        {
            return {key:"def"+`realtime`,value:{path:{pos:UtilsHelper.serializePos(origin),cache:ret.map(e=>e.direction).join("")}}}
        }
        
       throw new Error(`找不到路径 ${origin}->${goal}`)
    }
    public searchPathStepOneRoom(origin: RoomPosition,goal: RoomPosition,opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"] ) 
    {
        if(opt.IsEludeHostile)
        {
            decorates.push("c_elude");
        }

        const ret =  this.PathFinder.searchPathOneRoom(origin,goal,opt,decorates);
        return ret
    }
    /**
     *
     * @param origin    起始坐标
     * @param goal  目的地
     * @param opt   寻路参数
     * @param decorates cost设置回调
     * @param isRealtime 实时寻路不进行缓存查询
     * @returns
     */
    public searchPathCache(origin:RoomPosition,goal: { pos: RoomPosition; range: number },opt:IPathFinderOpt,decorates:CostKeys[]=["c_structure","c_creep","c_position"],isRealtime=false):ICacheResult<Readonly<INormalPath>>|false
    {
        if(isRealtime)
        {
            const path = this.PathFinder.searchPath(origin,goal,opt,decorates);
            if(path)
            {
                const pathcache =  UtilsHelper.serializePathResult(origin,path);
                return {key:"def"+`realtime`,value:{path:{pos:UtilsHelper.serializePos(origin),cache:pathcache.cache}}}
            }
            return false;
        }
        const pathcache = this.getPathCache(origin,goal.pos);
        if(pathcache)
        {
            return pathcache;
        }
        const path = this.PathFinder.searchPath(origin,goal,opt,decorates);
        if(path  )
        {
            const pathcache =  UtilsHelper.serializePathResult(origin,path);
            if(path.incomplete )
            {
                return {key:"def"+`incomplete`,value:{path:{pos:UtilsHelper.serializePos(origin),cache:pathcache.cache}}}
            }
            else
            {
                return this.insertPathCache( this.stanardkey(origin,goal.pos),origin,pathcache);
            }
        }
        return false;
    }
   
    private _findRoute(from:string,to:string,highwaycost=1):string[]|false
    {
        if(from ==to)
        {
            return [from];
        }
        if( PositionHelper.isNabRoom(from,to))
        {
            return [from,to];
        }

        let allowedRooms = { [ from ]: true,[ to ]: true };
        const rooms =  Game.map.findRoute(from, to, {routeCallback:(roomName)=>{
            let parsed = /^[WE]([0-9]+)[NS]([0-9]+)$/.exec(roomName);
            if(parsed)
            {
                let v1 = parseInt(parsed[1]);
                let v2 = parseInt(parsed[2]);
                let isHighway = ( v1 % 10 === 0) ||(v2 % 10 === 0);
                let isMyRoom = Game.rooms[roomName] &&Game.rooms[roomName].controller && Game.rooms[roomName].controller?.my;
                if(isHighway)
                {
                    return highwaycost;
                }
                if ( isMyRoom) {
                    return 1;
                } else {
                    if(this._avoidRooms[roomName] )
                    {
                        return 10;
                    }
                    return 2.5;
                }
            }
            return 2.5;
         }})

         if(rooms != -2 && rooms.length>0)
         {
            const roomsroute = _.map(rooms,e=>e.room);
            rooms.forEach(item=>{
                allowedRooms[item.room] = true;
            });
            // roomsroute.push(to)
            roomsroute.splice(0,0,from);
            return roomsroute;
         }
         return false;
    }
    private stanardkey(from:IRoomPosition,to:IRoomPosition):string
    {
        return `${UtilsHelper.serializePos(from)}_${UtilsHelper.serializePos(to)}`
    }
    /**
     * 普通路径
     * @param origin
     * @param goal
     * @returns
     */
    private getPathCache(origin:IRoomPosition,goal:IRoomPosition):ICacheResult< Readonly< INormalPath>>|undefined
    {

        const key =  this.stanardkey(origin,goal);

        const path = CacheOper.getCache(this._normal_paths,key)

        if(path)
        {
            return path;
        }
        return undefined;
    }
    
    private reversePath(path:Readonly< IStopPath>):IStopPath
    {
        if(path.path)
        {
            const origin = UtilsHelper.deserializePos(path.path.pos);
            const reversePos = UtilsHelper.deserializePath({pos:origin,cache:path.path.cache}).reverse();
            return {
                // stop_from:path.stop_to,
                // stop_to:path.stop_from,
                path:{
                    pos:UtilsHelper.serializePos( reversePos[0]),
                    cache:UtilsHelper.serializePath(reversePos)
                }
            }
        }
        throw new Error(`${JSON.stringify(path)} 路径不存在`);
    }
    private insertPathCache(pathkey:string,origin:IRoomPosition,path:IPathCache):ICacheResult< Readonly< INormalPath>>
    {
        const store_path:INormalPath = {

            path:{
                pos:UtilsHelper.serializePos(origin),
                cache:path.cache
            }
        }
        CacheOper.insertCache( this._normal_paths,store_path,pathkey)
        return {key:pathkey,value:store_path};
    }
    
    public getPathCacheByKey(key:string):INormalPath|undefined
    {
        const path = CacheOper.getCache(this._normal_paths,key);

        if(path)
        {
            return path.value;
        }
        return undefined;
    }
    public getPathByKey(key:string) 
    {
        const path = CacheOper.getCache(this._normal_paths,key);

        if(path)
        {
            return UtilsHelper.deserializePathCache( path.value.path);
        }
        return undefined;
    }
}
